--'------------------------------------------------------------------------------------------------------------------- --' Схема озвучки --' автор: Диденко Руслан (Stohe) --'-------------------------------------------------------------------------------------------------------------------- theme = {} can_play_sound = {} local sounds_base = stalker_ids.sound_script + 10000 function id() sounds_base = sounds_base + 1 return sounds_base - 1 end --'-------------------------------------------------------------------------------------------------------------------- --' Класс "звуковая коллекция сталкера" --'-------------------------------------------------------------------------------------------------------------------- class "npc_sound" function npc_sound:__init(snd_ini, section) --utils_data.debug_write("npc_sound:__init %s",section) self.class_id = "npc_sound" --' Параметры вычитывания звука self.prefix = snd_ini:r_bool_ex(section,"npc_prefix",false) self.path = snd_ini:r_string_ex(section,"path") or "" self.shuffle = snd_ini:r_string_ex(section,"shuffle") or "rnd" self.group_snd = snd_ini:r_bool_ex(section,"group_snd",false) self.play_always = snd_ini:r_bool_ex(section,"play_always",false) self.is_combat_sound = snd_ini:r_bool_ex(section,"is_combat_sound",false) self.dont_save = snd_ini:r_bool_ex(section,"dont_save",false) self.story_ids = snd_ini:line_exist(section,"story_ids") and parse_list(snd_ini,section,"story_ids",true) or nil self.section = section --' Хранит параметры звука для каждого NPC self.npc = {} self.played_id = nil -- Время задержки начала отыгрывания звука self.delay_sound = snd_ini:r_float_ex(section,"delay_sound") or 0 --' Интервал проигрывания звука local interval = parse_names(snd_ini:r_string_ex(section,"idle") or "3,5,100") self.min_idle = tonumber(interval[1]) self.max_idle = tonumber(interval[2]) self.rnd = tonumber(interval[3]) self.can_play_group_sound = true self.sound_path = {} self.faction = snd_ini:r_string_ex(section,"faction") or "" self.point = snd_ini:r_string_ex(section,"point") or "" self.msg = snd_ini:r_string_ex(section,"message") or "" self.avail_communities = snd_ini:line_exist(section,"avail_communities") and parse_list(snd_ini,section,"avail_communities",true) or nil end function npc_sound:reset(npc_id) local npc = db.storage[npc_id] and db.storage[npc_id].object self.played_time = nil self.played_id = nil self.can_play_group_sound = true can_play_sound[npc_id] = true if npc ~= nil then npc:set_sound_mask(-1) npc:set_sound_mask(0) end if self.pda_snd_obj ~= nil then self.pda_snd_obj:stop() self.pda_snd_obj = nil end end function npc_sound:is_playing(npc_id) -- Проверка играется ли сейчас звук у нпс local obj = db.storage[npc_id] and db.storage[npc_id].object if obj == nil then return false end return obj:active_sound_count() > 0 or (self.pda_snd_obj and self.pda_snd_obj:playing()) end function npc_sound:init_npc(npc) --utils_data.debug_write(strformat("npc_sound:init_npc %s",npc and npc:name())) local npc_id = npc:id() self.sound_path[npc_id] = {} local character_prefix if self.prefix == false then character_prefix = npc:sound_prefix() npc:sound_prefix("characters_voice\\") end local f = getFS() if f:exist("$game_sounds$",npc:sound_prefix()..self.path..".ogg") ~= nil then self.npc[npc_id] = {} self.npc[npc_id].id = id() self.sound_path[npc_id][1] = npc:sound_prefix()..self.path if self.is_combat_sound then self.npc[npc_id].max = npc:add_combat_sound(self.path, 64, snd_type.talk, 2, 1, self.npc[npc_id].id,"bip01_head") - 1 else self.npc[npc_id].max = npc:add_sound(self.path, 64, snd_type.talk, 2, 1, self.npc[npc_id].id) - 1 end else local num = 1 while f:exist("$game_sounds$",npc:sound_prefix()..self.path..num..".ogg") do -- printf("adding sound ["..npc:sound_prefix()..self.path..num.."] to table id = "..num) self.sound_path[npc_id][num] = npc:sound_prefix()..self.path..num num = num + 1 end if (num > 1) then self.npc[npc_id] = {} self.npc[npc_id].id = id() --printf("-Added sound [%s] for [%s]: %s", self.section, npc:section(), npc:sound_prefix() .. self.path) if self.is_combat_sound then self.npc[npc_id].max = npc:add_combat_sound(self.path, 64, snd_type.talk, 2, 1, self.npc[npc_id].id,"bip01_head") - 1 else self.npc[npc_id].max = npc:add_sound(self.path, 64, snd_type.talk, 2, 1, self.npc[npc_id].id) - 1 end elseif string.find(npc:section(),"sim_default") then printdbg("!Sound [%s] not found for [%s]: %s", self.section, npc:section(), npc:sound_prefix()..self.path) end end if not (self.npc[npc_id]) then return end if self.npc[npc_id].max == nil or self.npc[npc_id].max < 0 then abort("Couldnt find sounds %s with prefix %s", tostring(self.path), npc:sound_prefix()) return end if self.prefix == false then npc:sound_prefix(character_prefix) end if (self.group_snd) then self.can_play_group_sound = true end can_play_sound[npc_id] = true end function npc_sound:callback(npc_id) self.played_time = time_global() self.idle_time = math.random(self.min_idle, self.max_idle) * 1000 if (self.group_snd) then self.can_play_group_sound = true end can_play_sound[npc_id] = true -- printf("npc_sound:callback!!!!!!!!") -- get_hud():RemoveCustomStatic("cs_subtitles_npc") local st = db.storage[npc_id] if st.active_scheme == nil then return end if st[st.active_scheme].signals == nil then return end -- Затычка против возможного вылета, когда приходит колбек от звука, который данный НПС не играет. if self.npc[npc_id] == nil then return end if self.played_id == self.npc[npc_id].max and self.shuffle ~= "rnd" then --printf("npc [%s] signalled [theme_end] for snd [%s]", npc_id, self.section) st[st.active_scheme].signals["theme_end"] = true st[st.active_scheme].signals["sound_end"] = true else --printf("npc [%s] signalled [sound_end] for snd [%s]", npc_id, self.section) st[st.active_scheme].signals["sound_end"] = true end end function npc_sound:play(npc_id, faction, point) --utils_data.debug_write(strformat("npc_sound:play npc_id=%s faction=%s msg=%s",npc_id,faction,msg)) local npc = db.storage[npc_id] and db.storage[npc_id].object if npc == nil then printf("coudnt find npc!!!") return false end local npc_data = self.npc[npc_id] if not (npc_data) then return false end if (self.group_snd) then if (self.can_play_group_sound == false) then return false end elseif (can_play_sound[npc_id] == false) then return false end if self.played_time ~= nil and time_global() - self.played_time < self.idle_time then return false end self.played_time = nil self.played_id = self:select_next_sound(npc_id) if self.played_id == -1 then return false end npc:play_sound(npc_data.id, self.delay_sound+0.06, self.delay_sound+0.05, 1, 0, self.played_id) local table_id = self.played_id + 1 local snd = self.sound_path[npc_id][table_id] if not (snd) then printf("sound_theme.npc_sound:play() snd is nil! %s",self.section) return end if snd and npc:position():distance_to_sqr(db.actor:position()) >= 100 and getFS():exist("$game_sounds$", snd.."_pda.ogg") ~= nil then if self.pda_snd_obj ~= nil and self.pda_snd_obj:playing() then self.pda_snd_obj:stop() end self.pda_snd_obj = sound_object(snd.."_pda") --play_at_pos(CScriptGameObject *object, const Fvector &position, float delay, int flags) self.pda_snd_obj:play_at_pos(db.actor, VEC_ZERO, self.delay_sound, sound_object.s2d) self.pda_snd_obj.volume = 0.8 end --printf("snd_path is "..tostring(self.sound_path[npc_id][table_id])) local snd_st, num_copy = string.gsub(snd, "\\", "_") if (self.group_snd) then self.can_play_group_sound = false end can_play_sound[npc_id] = false if not closecaption.sound(snd, sound_object(snd):length(), npc, faction, point, self.delay_sound) then if game.translate_string(snd_st) ~= snd_st then faction = faction or character_community(npc) if not point then point = npc:profile_name().."_name" if game.translate_string(point) == point then point = nil end end news_manager.send_sound(npc, faction, point, snd, snd_st, self.delay_sound) else news_manager.send_sound(npc, faction, point, snd, nil , self.delay_sound) end end return true end function npc_sound:select_next_sound(npc_id) local npc_data = self.npc[npc_id] if not (npc_data and npc_data.max) then return 0 end if self.shuffle == "rnd" then if npc_data.max == 0 then return 0 end if self.played_id ~= nil then local played_id = math.random(0,npc_data.max - 1) if played_id >= self.played_id then return played_id + 1 end return played_id end return math.random(0,npc_data.max) end if self.shuffle == "seq" then if self.played_id == -1 then return -1 end if self.played_id == nil then return 0 end if self.played_id < npc_data.max then return self.played_id + 1 end return -1 end if self.shuffle == "loop" then if self.played_id == nil then return 0 end if self.played_id < npc_data.max then return self.played_id + 1 end return 0 end end function npc_sound:stop(obj_id) local npc = db.storage[obj_id] and db.storage[obj_id].object if npc ~= nil and npc:alive() then npc:set_sound_mask(-1) npc:set_sound_mask(0) end if self.pda_snd_obj ~= nil and self.pda_snd_obj:playing() then self.pda_snd_obj:stop() self.pda_snd_obj = nil end end function npc_sound:save_state(m_data) if (self.dont_save) then return end if (self.played_id) or (self.group_snd and self.can_play_group_sound == false) then m_data[self.section] = empty_table(m_data[self.section]) m_data[self.section].played_id = self.played_id or nil m_data[self.section].can_play_group_sound = self.can_play_group_sound == false and false or nil end end function npc_sound:load_state(m_data) if not (m_data[self.section]) then return end self.played_id = m_data[self.section].played_id if (self.group_snd) then self.can_play_group_sound = m_data[self.section].can_play_group_sound ~= false and true or false end end function npc_sound:save(thread) --utils_data.debug_write("npc_sound:save BEFORE") if self.dont_save then --utils_data.debug_write("npc_sound:save AFTER 1") return end -- set_save_marker(thread, "save", false, "npc_sound") utils_data.w_stpk(thread,"stringZ",tostring(self.played_id or nil),"npc_sound:save") if self.group_snd then thread:w_bool(self.can_play_group_sound == true) end --utils_data.debug_write("npc_sound:save AFTER 2") -- set_save_marker(thread, "save", true, "npc_sound") end function npc_sound:load(thread) --utils_data.debug_write("npc_sound:load BEFORE") if self.dont_save then --utils_data.debug_write("npc_sound:load AFTER 1") return end -- set_save_marker(thread, "load", false, "npc_sound") local id = thread:r_stringZ() if(id~="nil") then self.played_id = tonumber(id) else self.played_id = nil end if self.group_snd then self.can_play_group_sound = thread:r_bool() end --utils_data.debug_write("npc_sound:load AFTER 2") -- set_save_marker(thread, "load", true, "npc_sound") end function npc_sound:save_npc(thread, npc_id) --utils_data.debug_write("npc_sound:save_npc BEFORE") if self.dont_save then --utils_data.debug_write("npc_sound:save_npc AFTER 1") return end -- set_save_marker(thread, "save", false, "npc_sound_save_npc") if not self.group_snd then thread:w_bool(can_play_sound[npc_id] == true) end --utils_data.debug_write("npc_sound:save_npc AFTER 2") -- set_save_marker(thread, "save", true, "npc_sound_save_npc") end function npc_sound:load_npc(thread, npc_id) --utils_data.debug_write("npc_sound:load_npc BEFORE") if self.dont_save then --utils_data.debug_write("npc_sound:load_npc AFTER 1") return end -- set_save_marker(thread, "load", false, "npc_sound_save_npc") if not self.group_snd then can_play_sound[npc_id] = thread:r_bool() end --utils_data.debug_write("npc_sound:load_npc AFTER 2") -- set_save_marker(thread, "load", true, "npc_sound_save_npc") end --'-------------------------------------------------------------------------------------------------------------------- --' Класс "звуковая коллекция игрока" --'-------------------------------------------------------------------------------------------------------------------- class "actor_sound" function actor_sound:__init(snd_ini, section) self.class_id = "actor_sound" --' Параметры вычитывания звука self.stereo = snd_ini:r_bool_ex(section,"actor_stereo",false) self.prefix = snd_ini:r_bool_ex(section,"npc_prefix",false) self.path = snd_ini:r_string_ex(section,"path") or "" self.shuffle = snd_ini:r_string_ex(section,"shuffle") or "rnd" self.play_always = snd_ini:r_bool_ex(section,"play_always",false) self.section = section self.played_id = nil if self.prefix then self.path = "characters_voice\\"..self.path end --' Интервал проигрывания звука local interval = parse_names(snd_ini:r_string_ex(section,"idle") or "3,5,100") self.min_idle = tonumber(interval[1]) self.max_idle = tonumber(interval[2]) self.rnd = tonumber(interval[3]) self.sound = {} self.snd_obj = nil can_play_sound[0] = true self.faction = snd_ini:r_string_ex(section,"faction") or "" self.point = snd_ini:r_string_ex(section,"point") or "" self.msg = snd_ini:r_string_ex(section,"message") or "" local f = getFS() if f:exist("$game_sounds$",self.path..".ogg") ~= nil then self.sound[1] = self.path else local num = 1 while f:exist("$game_sounds$",self.path..num..".ogg") do self.sound[num] = self.path..num num = num + 1 end end if #self.sound == 0 then abort("There are no sound collection with path: %s", self.path) end end function actor_sound:callback(npc_id) self.played_time = time_global() self.idle_time = math.random(self.min_idle, self.max_idle) * 1000 self.snd_obj = nil can_play_sound[0] = true -- get_hud():RemoveCustomStatic("cs_subtitles_actor") -- printf("actor_sound:callback from [%s]", npc_id) local st = db.storage[npc_id] if st.active_scheme == nil then return end if st[st.active_scheme].signals == nil then -- printf("SOUND_THEME: There is no signals in this scheme [%s]", st.active_scheme) return end if self.played_id == #self.sound and self.shuffle ~= "rnd" then --printf("actor_sound:object [%s] signalled 'theme_end' in section [%s]", npc_id, st.active_section) st[st.active_scheme].signals["theme_end"] = true st[st.active_scheme].signals["sound_end"] = true else --printf("actor_sound:object [%s] signalled 'sound_end' in section [%s]", npc_id, st.active_section) st[st.active_scheme].signals["sound_end"] = true end end function actor_sound:is_playing () if(self.snd_obj~=nil) then return self.snd_obj:playing() else return false end end function actor_sound:play(obj_id, faction, point, sound) --printf("PLAY ACTOR SOUND") if (can_play_sound[0] == false) then return false end if self.played_time ~= nil and time_global() - self.played_time < self.idle_time then return false end self.played_time = nil self.played_id = self:select_next_sound() if self.played_id == -1 then return false end local snd = self.sound[self.played_id] if not (snd) then printf("sound_theme.actor_sound:play() snd is nil! %s",sound) return end self.snd_obj = sound_object(snd) self.snd_obj.volume = 0.8 self.snd_obj:play_at_pos(db.actor, VEC_ZERO, 0, sound_object.s2d) self.snd_obj.volume = 0.8 can_play_sound[0] = false if not closecaption.sound(snd, self.snd_obj:length(), db.actor, faction, nil, 0) then news_manager.send_sound(nil, faction, point, snd, nil, 0) end return true end function actor_sound:reset(npc_id) self.played_time = nil self.played_id = nil end function actor_sound:select_next_sound() local sound_table_size = #self.sound if self.shuffle == "rnd" then if sound_table_size == 1 then return 1 end if self.played_id ~= nil then local played_id = math.random(1,sound_table_size - 1) if played_id >= self.played_id then return played_id + 1 end return played_id end return math.random(1,sound_table_size) end if self.shuffle == "seq" then if self.played_id == -1 then return -1 end if self.played_id == nil then return 1 end if self.played_id < sound_table_size then return self.played_id + 1 end return -1 end if self.shuffle == "loop" then if self.played_id == nil then return 1 end if self.played_id < sound_table_size then return self.played_id + 1 end return 1 end end function actor_sound:stop() if self.snd_obj ~= nil then self.snd_obj:stop() end end function actor_sound:save(thread) -- set_save_marker(thread, "save", false, "actor_sound") utils_data.w_stpk(thread,"stringZ",tostring(self.played_id),"actor_sound:save") -- set_save_marker(thread, "save", true, "actor_sound") end function actor_sound:load(thread) -- set_save_marker(thread, "load", false, "actor_sound") local id = thread:r_stringZ() if(id~="nil") then self.played_id = tonumber(id) else self.played_id = nil end -- set_save_marker(thread, "load", true, "actor_sound") end function actor_sound:save_npc(thread) end function actor_sound:load_npc(thread) end function actor_sound:save_state(m_data) if (self.played_id) then m_data[self.section] = empty_table(m_data[self.section]) m_data[self.section].played_id = self.played_id end end function actor_sound:load_state(m_data) if not (m_data[self.section]) then return end self.played_id = m_data[self.section].played_id end --'-------------------------------------------------------------------------------------------------------------------- --' Класс "звуковая коллекция объекта" --'-------------------------------------------------------------------------------------------------------------------- class "object_sound" function object_sound:__init(snd_ini, section) self.class_id = "object_sound" --' Параметры вычитывания звука self.path = snd_ini:r_string_ex(section,"path") or "" self.shuffle = snd_ini:r_string_ex(section,"shuffle") or "rnd" --' Интервал проигрывания звука local interval = parse_names(snd_ini:r_string_ex(section,"idle") or "3,5,100") self.min_idle = tonumber(interval[1]) self.max_idle = tonumber(interval[2]) self.rnd = tonumber(interval[3]) self.sound = {} self.snd_obj = nil self.section = section self.played_id = nil self.faction = snd_ini:r_string_ex(section,"faction") or "" self.point = snd_ini:r_string_ex(section,"point") or "" self.msg = snd_ini:r_string_ex(section,"message") or "" local f = getFS() if f:exist("$game_sounds$",self.path..".ogg") ~= nil then self.sound[1] = self.path else local num = 1 while f:exist("$game_sounds$",self.path..num..".ogg") do self.sound[num] = self.path..num num = num + 1 end end if #self.sound == 0 then abort("There are no sound collection with path: %s", self.path) end end function object_sound:callback(npc_id) if not (self.cooldown) then self.cooldown = {} end if not (self.cooldown[npc_id]) then self.cooldown[npc_id] = time_global() + math.random(self.min_idle, self.max_idle) * 1000 end self.snd_obj = nil can_play_sound[npc_id] = true -- printf("object_sound:callback for object !!!!!!!!") -- get_hud():RemoveCustomStatic("cs_subtitles_object") local st = db.storage[npc_id] if not (st) then printf("object_sound:callback st is nil! how?") return end --printf("START object_sound:callback() %s scheme=%s st=%s signals=%s",st.object and st.object:name(),st.active_scheme,st[st.active_scheme],st[st.active_scheme].signals) if st.active_scheme == nil then return end if not (st[st.active_scheme] and st[st.active_scheme].signals) then return end if self.played_id == #self.sound and self.shuffle ~= "rnd" then st[st.active_scheme].signals["theme_end"] = true st[st.active_scheme].signals["sound_end"] = true else st[st.active_scheme].signals["sound_end"] = true end --printf("END object_sound:callback() %s",st.object and st.object:name()) end function object_sound:is_playing () if(self.snd_obj~=nil) then return self.snd_obj:playing() else return false end end function object_sound:play(obj_id, faction, point,sound) local obj = db.storage[obj_id] and db.storage[obj_id].object -- or level.object_by_id(obj_id) if obj == nil then return false end --printf("START object_sound:play() sound=%s %s[%s] can_play=%s",sound,obj:name(),obj_id,self.can_play_sound[obj_id] ~= false and true) if (can_play_sound[obj_id] == false) then return false end if (self.cooldown) then if (self.cooldown[obj_id] and time_global() < self.cooldown[obj_id]) then return false end self.cooldown[obj_id] = nil end self.played_id = self:select_next_sound() if self.played_id == -1 then return false end --printf("object played_id = %s", self.played_id) local snd = self.sound[self.played_id] if not (snd) then printf("sound_theme.object_sound:play() snd is nil! %s",sound) return end if snd and obj:position():distance_to_sqr(db.actor:position()) >= 5 and getFS():exist("$game_sounds$", snd.."_pda.ogg") ~= nil then self.pda_snd_obj = sound_object(snd.."_pda") self.pda_snd_obj:play_at_pos(db.actor, VEC_ZERO, 0, sound_object.s2d) self.pda_snd_obj.volume = 0.8 end self.snd_obj = sound_object(snd) self.snd_obj:play_at_pos(obj, obj:position(), 0, sound_object.s3d) can_play_sound[obj_id] = false if not closecaption.sound(snd, self.snd_obj:length(), obj, faction, point, 0) then news_manager.send_sound(nil, faction, point, snd) end --printf("END object_sound:play() sound=%s %s[%s]",sound,obj:name(),obj_id) return true end function object_sound:select_next_sound() local sound_table_size = #self.sound if self.shuffle == "rnd" then return math.random(1,sound_table_size) elseif self.shuffle == "seq" then if (self.played_id == nil) then return 1 elseif (self.played_id == -1) then return -1 elseif (self.played_id < sound_table_size) then return self.played_id + 1 else return -1 end elseif self.shuffle == "loop" then if self.played_id == nil then return 1 elseif self.played_id < sound_table_size then return self.played_id + 1 end return 1 end end function object_sound:stop() if self.snd_obj ~= nil then self.snd_obj:stop() end if self.pda_snd_obj ~= nil and self.pda_snd_obj:playing() then self.pda_snd_obj:stop() self.pda_snd_obj = nil end end function object_sound:save(thread) -- set_save_marker(thread, "save", false, "object_sound") utils_data.w_stpk(thread,"stringZ",tostring(self.played_id),"object_sound:save") -- set_save_marker(thread, "save", true, "object_sound") end function object_sound:load(thread) -- set_save_marker(thread, "load", false, "object_sound") local id = thread:r_stringZ() if(id~="nil") then self.played_id = tonumber(id) else self.played_id = nil end -- set_save_marker(thread, "load", true, "object_sound") end function object_sound:save_npc(thread) end function object_sound:load_npc(thread) end function object_sound:save_state(m_data) if (self.played_id) then m_data[self.section] = empty_table(m_data[self.section]) m_data[self.section].played_id = self.played_id end end function object_sound:load_state(m_data) if not (m_data[self.section]) then return end self.played_id = m_data[self.section].played_id end --'-------------------------------------------------------------------------------------------------------------------- --' Класс "зацикленный звук" --'-------------------------------------------------------------------------------------------------------------------- class "looped_sound" function looped_sound:__init(snd_ini, section) self.class_id = "looped_sound" --' Параметры вычитывания звука self.path = snd_ini:r_string_ex(section,"path") or "" self.sound = nil self.snd_obj = nil self.section = section local f = getFS() if f:exist("$game_sounds$",self.path..".ogg") ~= nil then self.sound = self.path end if self.sound == nil then abort("There are no looped sound with path: %s", self.path) end end function looped_sound:is_playing () if(self.snd_obj~=nil) then return self.snd_obj:playing() else return false end end function looped_sound:stop () if self.snd_obj ~= nil then self.snd_obj:stop() end end function looped_sound:set_volume (level) self.snd_obj.volume = level end function looped_sound:play(obj_id) local obj = db.storage[obj_id].object if obj == nil then return end self.snd_obj = self.snd_obj or sound_object(self.sound) self.snd_obj:play_at_pos(obj, obj:position(), 0, sound_object.s3d + sound_object.looped) return true end function looped_sound:save(thread) -- set_save_marker(thread, "save", false, "looped_sound") -- set_save_marker(thread, "save", true, "looped_sound") end function looped_sound:load(thread) -- set_save_marker(thread, "load", false, "looped_sound") -- set_save_marker(thread, "load", true, "looped_sound") end function looped_sound:save_npc(thread) end function looped_sound:load_npc(thread) end function looped_sound:save_state(m_data) end function looped_sound:load_state(m_data) end --'-------------------------------------------------------------------------------------------------------------------- --' Загрузка звуков --'-------------------------------------------------------------------------------------------------------------------- function load_sound() local snd_ini = ini_file("misc\\sound\\script_sound.ltx") local function itr(section) local level_list = snd_ini:line_exist(section,"levels") and parse_list(snd_ini,section,"levels",true) or nil if (level_list == nil or level_list[level.name()]) then local type = snd_ini:r_string_ex(section,"type") or "" if type == "npc" then theme[section] = theme[section] or npc_sound(snd_ini, section) elseif type == "actor" then theme[section] = theme[section] or actor_sound(snd_ini, section) elseif type == "3d" then theme[section] = theme[section] or object_sound(snd_ini, section) elseif type == "looped" then theme[section] = theme[section] or looped_sound(snd_ini, section) end end return false end snd_ini:section_for_each(itr) end --' Загрузка звуков НПС function init_npc_sound(npc) for k,v in pairs(theme) do if v.init_npc then --printf("checking %s for %s (%s)", v.section, npc:name(), character_community(npc)) if (v.avail_communities == nil or v.avail_communities[character_community(npc)]) then if (v.story_ids == nil or v.story_ids[ get_object_story_id(npc:id()) or ""]) then v:init_npc(npc) end end end end end